package org.iabako.server.dao.business;

import org.iabako.server.dao.JpaDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.business.Installment;
import org.iabako.shared.entity.business.PaymentRequestConfig;
import org.iabako.shared.entity.business.Sale;
import org.springframework.stereotype.Repository;

import javax.persistence.Query;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 02/09/14.
 */
@Repository("installmentDAO")
public class InstallmentDAO extends JpaDAO<Long, Installment> {

    @Override
    protected String getUniqueNumberVerificationQuery() {
        return null;
    }

    @Override
    protected String getLastNumberQuery() {
        return null;
    }

    public List<Installment> findBySale(Sale sale) {
        String query = "SELECT installment from Installment installment where installment.sale = :sale";
        return (List<Installment>) entityManager.createQuery(query).setParameter("sale", sale).getResultList();
    }

    private String getInstallmentsForPaymentRequestSuffix(Date afterDate, Date beforeDate, boolean beforePaymentEmail) {
        //join Client is mandatory (we do this to send an email to clients)
        String queryString = " FROM Installment i join i.sale sale join sale.client client " +
                "WHERE sale.enterprise = :enterprise AND client.email IS NOT NULL ";

        if (afterDate != null) {
            queryString += "AND i.date >= :afterDate ";
        }

        if (beforeDate != null) {
            queryString += "AND i.date < :beforeDate ";
        }

        if (beforePaymentEmail) {
            queryString += "AND i.requestBeforeDateSent = 0";
        } else {
            queryString += "AND i.requestAfterDateSent = 0";
        }

        return queryString;
    }

    private void addParamsTOInstallmentsForPaymentRequestQuery(Query query, Date afterDate, Date beforeDate) {
        if (afterDate != null) {
            query.setParameter("afterDate", afterDate);
        }

        if (beforeDate != null) {
            query.setParameter("beforeDate", beforeDate);
        }
    }

    public List<Installment> getInstallmentsForRequestBetween(PaymentRequestConfig payReqConf, boolean beforePaymentEmail) {

        if (beforePaymentEmail && payReqConf.getDaysBeforePayment() < 0) {
            return new ArrayList<Installment>();
        }
        if (!beforePaymentEmail && payReqConf.getDaysAfterPayment() < 0) {
            return new ArrayList<Installment>();
        }

        Date dateAfter = getDateAfterForPaymentRequest(beforePaymentEmail);
        Date dateBefore = getDateBeforeForPaymentRequest(payReqConf, beforePaymentEmail);

        String queryString = "SELECT i " + getInstallmentsForPaymentRequestSuffix(dateAfter, dateBefore, beforePaymentEmail);

        Query query = entityManager.createQuery(queryString).
                setParameter("enterprise", payReqConf.getEnterprise());

        addParamsTOInstallmentsForPaymentRequestQuery(query, dateAfter, dateBefore);

        return (List<Installment>) query.getResultList();
    }

    public void setRequestPaymentSent(Installment installment, boolean beforePaymentMail) {
        String query = "";
        if (beforePaymentMail) {
            query = "UPDATE Installment i SET i.requestBeforeDateSent = 1, i.requestBeforeDate = now() WHERE i.id =:id";
        } else {
            query = "UPDATE Installment i SET i.requestAfterDateSent = 1, i.requestAfterDate = now() WHERE i.id =:id";
        }

        entityManager.createQuery(query).setParameter("id", installment.getId()).executeUpdate();
    }

    public int getNumberOfInstallmentsForRequest(PaymentRequestConfig payReqConf, boolean beforePaymentMail) {

        if (beforePaymentMail && payReqConf.getDaysBeforePayment() < 0) {
            return 0;
        }
        if (!beforePaymentMail && payReqConf.getDaysAfterPayment() < 0) {
            return 0;
        }

        Date dateAfter = getDateAfterForPaymentRequest(beforePaymentMail);
        Date dateBefore = getDateBeforeForPaymentRequest(payReqConf, beforePaymentMail);

        String queryString = "SELECT COUNT (i) " + getInstallmentsForPaymentRequestSuffix(dateAfter, dateBefore, beforePaymentMail);

        Query query = entityManager.createQuery(queryString).
                setParameter("enterprise", getSessionUser().getEnterprise());

        addParamsTOInstallmentsForPaymentRequestQuery(query, dateAfter, dateBefore);

        return ((Long) query.getSingleResult()).intValue();
    }

    private Date getDateAfterForPaymentRequest(boolean beforePaymentMail) {
        ServerTools serverTools = new ServerTools();

        if (beforePaymentMail) {
            return serverTools.resetTime(new Date());
        } else {
            return null;
        }
    }

    private Date getDateBeforeForPaymentRequest(PaymentRequestConfig payReqConf, boolean beforePaymentMail) {
        ServerTools serverTools = new ServerTools();

        if (beforePaymentMail) {
            return serverTools.addDaysToDate(serverTools.resetTime(new Date()), payReqConf.getDaysBeforePayment() + 1);

        } else {
            return serverTools.addDaysToDate(serverTools.resetTime(new Date()), (payReqConf.getDaysAfterPayment() - 1) * -1);
        }
    }
}
